package io.renren.common.utils;

import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * 高精度数值计算工具类
 *
 */
public class BigNumber {
	private BigNumber() {
		// 这个类不能外部实例化
	}

	/**
	 * 提供精确的加法运算(string参数)
	 *
	 * @param v1
	 * @param v2
	 * @return
	 */
	public static BigDecimal add(String v1, String v2) {
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.add(b2);
	}

	/**
	 * 提供精确的加法运算(double参数)
	 *
	 * @param v1
	 * @param v2
	 * @return
	 */
	public static BigDecimal add(double v1, double v2) {
		return add(String.valueOf(v1), String.valueOf(v2));
	}

	/**
	 * 提供精确的减法运算(string参数)
	 *
	 * @param v1
	 * @param v2
	 * @return
	 */
	public static BigDecimal sub(String v1, String v2) {
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.subtract(b2);
	}

	/**
	 * 提供精确的减法运算(double参数)
	 *
	 * @param v1
	 * @param v2
	 * @return
	 */
	public static BigDecimal sub(double v1, double v2) {
		return sub(String.valueOf(v1), String.valueOf(v2));
	}

	/**
	 * 提供精确的乘法运算(string参数)
	 *
	 * @param v1
	 * @param v2
	 * @return
	 */
	public static BigDecimal mul(String v1, String v2) {
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.multiply(b2);
	}

	/**
	 * 提供精确的乘法运算(double参数)
	 *
	 * @param v1
	 * @param v2
	 * @return
	 */
	public static BigDecimal mul(double v1, double v2) {
		return mul(String.valueOf(v1), String.valueOf(v2));
	}

	/**
	 * 提供（相对）精确的除法运算(string参数)
	 *
	 * @param v1
	 * @param v2
	 * @param scale
	 * @return
	 */
	public static BigDecimal div(String v1, String v2, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP);
	}

	/**
	 * 提供（相对）精确的除法运算(double参数)
	 *
	 * @param v1
	 * @param v2
	 * @param scale
	 * @return
	 */
	public static BigDecimal div(double v1, double v2, int scale) {
		return div(String.valueOf(v1), String.valueOf(v2), scale);
	}

	/**
	 * 提供精确的小数位四舍五入处理(string参数)
	 *
	 * @param v
	 * @param scale
	 * @return
	 */
	public static BigDecimal round(String v, int scale) {
		return div(v, "1", scale);
	}

	/**
	 * 提供精确的小数位四舍五入处理(double参数)
	 *
	 * @param v
	 * @param scale
	 * @return
	 */
	public static BigDecimal round(double v, int scale) {
		return round(String.valueOf(v), scale);
	}

	/**
	 * 计算阶乘
	 *
	 * @param n
	 * @return
	 */
	public static BigInteger getFactorial(int n) {
		if (n < 0) {
			throw new IllegalArgumentException("n必须大于等于0");
		} else if (n == 0) {
			return new BigInteger("0");
		}
		BigInteger result = new BigInteger("1");
		for (; n > 0; n--) {
			result = result.multiply(new BigInteger(new Integer(n).toString()));
		}
		return result;
	}
}
